#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <sstream>

using namespace std;

// 定义边结构
struct Edge {
    char u, v;
    int weight;
    Edge(char _u, char _v, int _weight) : u(_u), v(_v), weight(_weight) {}
};

// 并查集数据结构
class UnionFind {
private:
    unordered_map<char, char> parent;
public:
    UnionFind(const vector<char>& nodes) {
        for (char node : nodes) {
            parent[node] = node;
        }
    }

    char find(char node) {
        if (parent[node] != node) {
            parent[node] = find(parent[node]); // 路径压缩
        }
        return parent[node];
    }

    void unite(char node1, char node2) {
        char root1 = find(node1);
        char root2 = find(node2);
        if (root1 != root2) {
            parent[root2] = root1; // 合并集合
        }
    }
};

// 比较函数，用于排序边
bool compareEdges(const Edge& a, const Edge& b) {
    return a.weight < b.weight;
}

int kruskalMST(vector<Edge>& edges, const vector<char>& nodes) {
    UnionFind uf(nodes);
    sort(edges.begin(), edges.end(), compareEdges);

    int mstWeight = 0;
    for (const Edge& edge : edges) {
        if (uf.find(edge.u) != uf.find(edge.v)) {
            uf.unite(edge.u, edge.v);
            mstWeight += edge.weight;
        }
    }

    return mstWeight;
}

int main() {
    int numNodes;
    cin >> numNodes;

    vector<char> nodes(numNodes);
    for (int i = 0; i < numNodes; ++i) {
        cin >> nodes[i];
    }

    cin.ignore(); // 忽略换行符

    vector<Edge> edges;
    string line;
    while (getline(cin, line)) {
        if (line.empty()) break; // 遇到空行停止读取
        istringstream iss(line);
        char u, v;
        int weight;
        iss >> u >> v >> weight;
        edges.emplace_back(u, v, weight);
    }

    int mstWeight = kruskalMST(edges, nodes);
    cout << mstWeight << endl;

    return 0;
}